0246. references 项目引用
1. 🎯 本节内容
- 项目引用(Project References)
- composite 选项
- 依赖关系管理
- 增量构建
- Monorepo 应用
- 构建模式选项
2. 🫧 评价
项目引用允许将 TypeScript 项目拆分为多个独立部分,实现更快的构建和更好的代码组织。
- 支持大型项目拆分
- 实现增量构建
- 强制执行依赖关系
- 提高构建性能
- 是 Monorepo 的基础
- 需要合理的项目结构
3. 🤔 项目引用是什么?
3.1. 基本概念
项目引用允许 TypeScript 项目依赖其他 TypeScript 项目,每个项目可以独立构建。
text
项目结构:
my-workspace/
├── packages/
│ ├── core/
│ │ ├── src/
│ │ ├── dist/
│ │ └── tsconfig.json
│ ├── utils/
│ │ ├── src/
│ │ ├── dist/
│ │ └── tsconfig.json
│ └── app/
│ ├── src/
│ ├── dist/
│ └── tsconfig.json
└── tsconfig.json1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.2. composite 选项
要使用项目引用,被引用的项目必须启用 composite。
json
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
3.3. references 配置
json
// packages/app/tsconfig.json
{
"compilerOptions": {
"outDir": "./dist"
},
"references": [{ "path": "../core" }, { "path": "../utils" }]
}1
2
3
4
5
6
7
2
3
4
5
6
7
4. 🤔 为什么需要项目引用?
4.1. 构建性能
text
❌ 单体项目(慢):
- 每次都编译所有文件
- 修改一个文件,全部重新编译
✅ 项目引用(快):
- 只编译修改的项目
- 依赖项使用缓存的构建结果
- 并行构建独立项目1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
4.2. 代码组织
ts
// ❌ 没有项目引用(混乱)
import { User } from '../../core/src/models/user'
import { helper } from '../../utils/src/helper'
// ✅ 使用项目引用(清晰)
import { User } from '@my-workspace/core'
import { helper } from '@my-workspace/utils'1
2
3
4
5
6
7
2
3
4
5
6
7
4.3. 强制依赖关系
text
项目引用强制执行依赖方向:
core (无依赖)
↑
utils (依赖 core)
↑
app (依赖 core 和 utils)
❌ 不允许:core 依赖 app(循环依赖)1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
5. 🤔 如何配置项目引用?
5.1. 基础配置
text
项目结构:
workspace/
├── packages/
│ ├── shared/
│ │ ├── src/index.ts
│ │ └── tsconfig.json
│ └── main/
│ ├── src/index.ts
│ └── tsconfig.json
└── tsconfig.json1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
json
// packages/shared/tsconfig.json(被引用项目)
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
// packages/main/tsconfig.json(引用项目)
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"rootDir": "./src"
},
"references": [
{ "path": "../shared" }
],
"include": ["src/**/*"]
}
// 根 tsconfig.json(协调器)
{
"files": [],
"references": [
{ "path": "./packages/shared" },
{ "path": "./packages/main" }
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
5.2. Monorepo 完整示例
text
my-monorepo/
├── packages/
│ ├── types/ (共享类型)
│ ├── utils/ (工具函数)
│ ├── core/ (核心逻辑)
│ ├── ui/ (UI 组件)
│ └── app/ (应用入口)
└── tsconfig.json1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
json
// packages/types/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist"
}
}
// packages/utils/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist"
},
"references": [
{ "path": "../types" }
]
}
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist"
},
"references": [
{ "path": "../types" },
{ "path": "../utils" }
]
}
// packages/app/tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist"
},
"references": [
{ "path": "../types" },
{ "path": "../utils" },
{ "path": "../core" },
{ "path": "../ui" }
]
}
// 根 tsconfig.json
{
"files": [],
"references": [
{ "path": "./packages/types" },
{ "path": "./packages/utils" },
{ "path": "./packages/core" },
{ "path": "./packages/ui" },
{ "path": "./packages/app" }
]
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
5.3. path 选项
json
{
"references": [
{ "path": "../shared" }, // 相对路径
{ "path": "./packages/core" }, // 相对路径
{ "path": "../utils/tsconfig.json" } // 指定配置文件
]
}1
2
3
4
5
6
7
2
3
4
5
6
7
5.4. prepend 选项
json
{
"references": [
{
"path": "../shared",
"prepend": true // 将依赖的输出添加到此项目输出之前
}
]
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
6. 🤔 如何构建项目引用?
6.1. 使用 --build 模式
bash
# 构建整个项目(包括依赖)
tsc --build
# 或使用简写
tsc -b
# 指定配置文件
tsc -b tsconfig.json
# 构建特定项目
tsc -b packages/app1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
6.2. 增量构建
bash
# 增量构建(只构建修改的部分)
tsc -b
# 强制完全重新构建
tsc -b --force
# 清理构建产物
tsc -b --clean
# 查看会构建什么(不实际构建)
tsc -b --dry1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
6.3. 监听模式
bash
# 监听模式
tsc -b --watch
# 或简写
tsc -b -w1
2
3
4
5
2
3
4
5
6.4. 并行构建
TypeScript 自动并行构建独立的项目。
bash
# 自动并行构建
tsc -b
# packages/types 和 packages/utils 可能同时构建
# packages/core 等待它们完成后构建1
2
3
4
5
2
3
4
5
6.5. package.json 脚本
json
{
"scripts": {
"build": "tsc -b",
"build:force": "tsc -b --force",
"clean": "tsc -b --clean",
"watch": "tsc -b --watch",
"dev": "tsc -b -w"
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
7. 🤔 使用时需要注意什么?
7.1. composite 必需选项
json
// ❌ 错误:被引用的项目必须启用 composite
{
"compilerOptions": {
"outDir": "./dist"
}
}
// ✅ 正确
{
"compilerOptions": {
"composite": true,
"declaration": true, // composite 要求启用
"outDir": "./dist"
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.2. declaration 自动启用
json
{
"compilerOptions": {
"composite": true,
"declaration": true // composite 强制启用此选项
}
}1
2
3
4
5
6
2
3
4
5
6
7.3. 输出文件位置
json
{
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"declarationDir": "./types" // ❌ composite 不允许分离
}
}
// ✅ 正确:声明文件和 JS 文件在同一目录
{
"compilerOptions": {
"composite": true,
"outDir": "./dist"
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.4. 循环依赖检测
text
A → B → C → A
❌ 错误:检测到循环依赖
error TS6202: Project references may not form a circular graph.1
2
3
4
2
3
4
7.5. rootDir 限制
json
{
"compilerOptions": {
"composite": true,
"rootDir": "./src" // ✅ 明确指定
},
"include": ["src/**/*"]
}1
2
3
4
5
6
7
2
3
4
5
6
7
7.6. tsbuildinfo 文件
text
项目构建时生成 .tsbuildinfo 文件:
packages/core/
├── dist/
│ └── index.js
└── tsconfig.tsbuildinfo ← 增量构建信息1
2
3
4
5
6
2
3
4
5
6
json
{
"compilerOptions": {
"composite": true,
"incremental": true,
"tsBuildInfoFile": "./dist/.tsbuildinfo" // 自定义位置
}
}1
2
3
4
5
6
7
2
3
4
5
6
7
7.7. 导入路径
ts
// ❌ 不要直接导入源文件
import { User } from "../shared/src/user";
// ✅ 通过构建产物导入
import { User } from "../shared";
// package.json
{
"name": "@workspace/shared",
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
7.8. path 别名
json
// 根 tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@workspace/*": ["packages/*/src"]
}
}
}
// 使用
import { User } from "@workspace/core";1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
7.9. 构建顺序
text
TypeScript 自动确定构建顺序:
依赖关系:
types → utils → core → app
构建顺序:
1. types (无依赖,先构建)
2. utils (依赖 types)
3. core (依赖 types 和 utils)
4. app (依赖所有)1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
7.10. .gitignore 配置
text
# .gitignore
*.tsbuildinfo
packages/*/dist
packages/*/.tsbuildinfo1
2
3
4
2
3
4
7.11. 编辑器支持
json
// VS Code 自动识别项目引用
// 提供跨项目的类型检查和导航1
2
2
7.12. 性能优化
bash
# 只构建修改的项目
tsc -b
# 使用 --verbose 查看构建过程
tsc -b --verbose
# 示例输出:
# Projects in this build:
# * packages/types/tsconfig.json
# * packages/utils/tsconfig.json
# * packages/core/tsconfig.json
# Project 'types' is up to date
# Project 'utils' is up to date
# Building project 'core'...1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14